<template>
  <div 
    :class="[
      'bx-slider',
      {
        'bx-slider--disabled': disabled,
        'bx-slider--vertical': vertical
      }
    ]"
    @click="handleTrackClick"
  >
    <div 
      ref="trackRef"
      class="bx-slider__track"
    >
      <div 
        class="bx-slider__rail"
        :style="railStyle"
      ></div>
      
      <div 
        class="bx-slider__handle"
        :style="handleStyle"
        @mousedown="handleMouseDown"
        @touchstart="handleTouchStart"
      >
        <div class="bx-slider__handle-inner"></div>
      </div>
      
      <!-- 刻度标记 -->
      <div 
        v-if="marks && Object.keys(marks).length"
        class="bx-slider__marks"
      >
        <div
          v-for="(mark, value) in marks"
          :key="value"
          :class="[
            'bx-slider__mark',
            {
              'bx-slider__mark--active': Number(value) <= currentValue
            }
          ]"
          :style="getMarkStyle(Number(value))"
        >
          <div class="bx-slider__mark-dot"></div>
          <div class="bx-slider__mark-text">{{ mark }}</div>
        </div>
      </div>
    </div>
    
    <!-- 提示信息 -->
    <div 
      v-if="showTooltip && isDragging"
      class="bx-slider__tooltip bx-glass"
      :style="tooltipStyle"
    >
      {{ tooltipFormatter ? tooltipFormatter(currentValue) : currentValue }}
    </div>
  </div>
</template>

<script>
import { ref, computed, onMounted, onUnmounted } from 'vue'

export default {
  name: 'BxSlider',
  props: {
    modelValue: {
      type: Number,
      default: 0
    },
    min: {
      type: Number,
      default: 0
    },
    max: {
      type: Number,
      default: 100
    },
    step: {
      type: Number,
      default: 1
    },
    disabled: {
      type: Boolean,
      default: false
    },
    vertical: {
      type: Boolean,
      default: false
    },
    showTooltip: {
      type: Boolean,
      default: true
    },
    tooltipFormatter: {
      type: Function,
      default: undefined
    },
    marks: {
      type: Object,
      default: () => ({})
    }
  },
  emits: ['update:modelValue', 'change'],
  setup(props, { emit }) {
    const trackRef = ref(null)
    const isDragging = ref(false)
    const currentValue = ref(props.modelValue)

    const percentage = computed(() => {
      return ((currentValue.value - props.min) / (props.max - props.min)) * 100
    })

    const railStyle = computed(() => {
      if (props.vertical) {
        return {
          height: `${percentage.value}%`
        }
      }
      return {
        width: `${percentage.value}%`
      }
    })

    const handleStyle = computed(() => {
      if (props.vertical) {
        return {
          bottom: `${percentage.value}%`
        }
      }
      return {
        left: `${percentage.value}%`
      }
    })

    const tooltipStyle = computed(() => {
      if (props.vertical) {
        return {
          bottom: `${percentage.value}%`,
          left: '100%',
          marginLeft: '12px',
          marginBottom: '-16px'
        }
      }
      return {
        left: `${percentage.value}%`,
        top: '-40px',
        transform: 'translateX(-50%)'
      }
    })

    const getMarkStyle = (value) => {
      const percent = ((value - props.min) / (props.max - props.min)) * 100
      
      if (props.vertical) {
        return {
          bottom: `${percent}%`
        }
      }
      return {
        left: `${percent}%`
      }
    }

    const updateValue = (newValue) => {
      // 限制在范围内
      newValue = Math.max(props.min, Math.min(props.max, newValue))
      
      // 应用步长
      if (props.step > 0) {
        const steps = Math.round((newValue - props.min) / props.step)
        newValue = props.min + steps * props.step
      }
      
      if (newValue !== currentValue.value) {
        currentValue.value = newValue
        emit('update:modelValue', newValue)
        emit('change', newValue)
      }
    }

    const getValueFromPosition = (clientX, clientY) => {
      if (!trackRef.value) return currentValue.value
      
      const rect = trackRef.value.getBoundingClientRect()
      let percentage
      
      if (props.vertical) {
        percentage = (rect.bottom - clientY) / rect.height
      } else {
        percentage = (clientX - rect.left) / rect.width
      }
      
      percentage = Math.max(0, Math.min(1, percentage))
      return props.min + percentage * (props.max - props.min)
    }

    const handleTrackClick = (event) => {
      if (props.disabled || isDragging.value) return
      
      const newValue = getValueFromPosition(event.clientX, event.clientY)
      updateValue(newValue)
    }

    const handleMouseDown = (event) => {
      if (props.disabled) return
      
      event.preventDefault()
      isDragging.value = true
      
      const handleMouseMove = (e) => {
        const newValue = getValueFromPosition(e.clientX, e.clientY)
        updateValue(newValue)
      }
      
      const handleMouseUp = () => {
        isDragging.value = false
        document.removeEventListener('mousemove', handleMouseMove)
        document.removeEventListener('mouseup', handleMouseUp)
      }
      
      document.addEventListener('mousemove', handleMouseMove)
      document.addEventListener('mouseup', handleMouseUp)
    }

    const handleTouchStart = (event) => {
      if (props.disabled) return
      
      event.preventDefault()
      isDragging.value = true
      
      const handleTouchMove = (e) => {
        const touch = e.touches[0]
        const newValue = getValueFromPosition(touch.clientX, touch.clientY)
        updateValue(newValue)
      }
      
      const handleTouchEnd = () => {
        isDragging.value = false
        document.removeEventListener('touchmove', handleTouchMove)
        document.removeEventListener('touchend', handleTouchEnd)
      }
      
      document.addEventListener('touchmove', handleTouchMove, { passive: false })
      document.addEventListener('touchend', handleTouchEnd)
    }

    // 监听外部值变化
    const unwatchValue = () => {
      return () => {
        currentValue.value = props.modelValue
      }
    }

    onMounted(() => {
      currentValue.value = props.modelValue
    })

    return {
      trackRef,
      isDragging,
      currentValue,
      railStyle,
      handleStyle,
      tooltipStyle,
      getMarkStyle,
      handleTrackClick,
      handleMouseDown,
      handleTouchStart
    }
  }
}
</script>

<style scoped>
.bx-slider {
  position: relative;
  padding: 8px 0;
  cursor: pointer;
  font-family: var(--bx-font-family);
}

.bx-slider--vertical {
  width: 16px;
  height: 200px;
  padding: 0 8px;
}

.bx-slider--disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.bx-slider__track {
  position: relative;
  width: 100%;
  height: 4px;
  background: var(--bx-glass-border);
  border-radius: 2px;
}

.bx-slider--vertical .bx-slider__track {
  width: 4px;
  height: 100%;
}

.bx-slider__rail {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  background: rgba(0, 122, 255, 0.6);
  border-radius: inherit;
  transition: all var(--bx-transition-medium);
}

.bx-slider__handle {
  position: absolute;
  top: 50%;
  width: 16px;
  height: 16px;
  margin-top: -8px;
  margin-left: -8px;
  cursor: grab;
  transition: all var(--bx-transition-medium);
}

.bx-slider--vertical .bx-slider__handle {
  left: 50%;
  top: auto;
  margin-left: -8px;
  margin-bottom: -8px;
}

.bx-slider__handle:active {
  cursor: grabbing;
}

.bx-slider__handle-inner {
  width: 100%;
  height: 100%;
  background: var(--bx-glass-bg);
  backdrop-filter: var(--bx-glass-blur);
  border: 2px solid rgba(0, 122, 255, 0.6);
  border-radius: 50%;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  transition: all var(--bx-transition-medium);
}

.bx-slider__handle:hover .bx-slider__handle-inner {
  border-color: rgba(0, 122, 255, 0.8);
  transform: scale(1.2);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}

.bx-slider__marks {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: 20px;
}

.bx-slider--vertical .bx-slider__marks {
  top: 0;
  left: 100%;
  bottom: 0;
  right: auto;
  width: 60px;
  height: auto;
}

.bx-slider__mark {
  position: absolute;
  transform: translateX(-50%);
}

.bx-slider--vertical .bx-slider__mark {
  transform: translateY(50%);
}

.bx-slider__mark-dot {
  width: 6px;
  height: 6px;
  background: var(--bx-glass-border);
  border-radius: 50%;
  margin: 0 auto 4px;
  transition: background-color var(--bx-transition-medium);
}

.bx-slider--vertical .bx-slider__mark-dot {
  margin: 0 4px 0 0;
  display: inline-block;
}

.bx-slider__mark--active .bx-slider__mark-dot {
  background: rgba(0, 122, 255, 0.6);
}

.bx-slider__mark-text {
  font-size: 12px;
  color: var(--bx-text-tertiary);
  text-align: center;
  white-space: nowrap;
}

.bx-slider--vertical .bx-slider__mark-text {
  display: inline-block;
  vertical-align: middle;
  margin-left: 4px;
}

.bx-slider__tooltip {
  position: absolute;
  padding: 4px 8px;
  background: var(--bx-glass-bg);
  backdrop-filter: var(--bx-glass-blur-strong);
  border: 1px solid var(--bx-glass-border);
  border-radius: var(--bx-radius-small);
  font-size: 12px;
  color: var(--bx-text-primary);
  white-space: nowrap;
  z-index: 1000;
  pointer-events: none;
}

.bx-slider__tooltip::before {
  content: '';
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 4px solid transparent;
  border-top-color: var(--bx-glass-border);
}

.bx-slider--vertical .bx-slider__tooltip::before {
  top: 50%;
  left: -4px;
  transform: translateY(-50%);
  border: 4px solid transparent;
  border-right-color: var(--bx-glass-border);
}

/* 响应式设计 */
@media (max-width: 768px) {
  .bx-slider {
    padding: 12px 0;
  }
  
  .bx-slider--vertical {
    padding: 0 12px;
  }
  
  .bx-slider__handle {
    width: 20px;
    height: 20px;
    margin-top: -10px;
    margin-left: -10px;
  }
  
  .bx-slider--vertical .bx-slider__handle {
    margin-left: -10px;
    margin-bottom: -10px;
  }
}
</style>

